//******************************************************************
//******************************************************************
//**********          ANts Peer To Peer Sources        *************
//
// ANts P2P realizes a third generation P2P net. It protects your
// privacy while you are connected and makes you not trackable, hiding
// your identity (ip) and crypting everything you are sending/receiving
// from others.

// Copyright (C) 2004  Roberto Rossi

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

package ants.p2p;

import ants.p2p.query.QueryMessage;

import java.io.*;
import javax.crypto.*;
import java.math.*;

public class Message implements Serializable, Cloneable{
  private final String antMessageVersion = Ant.getProtocolVersion();

  private int retransmissions;
  private boolean delivered = false;
  private String source;
  private String sourceAddress;
  protected String dest;
  private String ack_id;
  private byte[] signature = null;
  private byte[] publicKey = null;
  private int type;

  public Message(Message m){
    this.source = m.source;
    this.sourceAddress = m.sourceAddress;
    this.dest = m.dest;
    this.ack_id = m.ack_id;
    this.type = m.type;
    this.delivered = m.delivered;
    this.retransmissions = m.retransmissions;
    this.signature = m.signature;
    this.publicKey = m.publicKey;
  }

  public Message getSignableMessage(){
    try{
      Message signable = (Message)this.clone();
      signable.retransmissions = 0;
      signable.delivered = false;
      signable.signature = null;
      signable.publicKey = null;
      return signable;
    }catch(Exception e){
      e.printStackTrace();
      return null;
    }
  }

  public void setSignature(byte[] signature){
    this.signature = signature;
  }

  public byte[] getSignature(){
    return this.signature;
  }

  public void setPublicKey(byte[] pubKey){
    this.publicKey = pubKey;
  }

  public byte[] getPublicKey(){
    return this.publicKey;
  }

  public String getVersion(){
    return antMessageVersion;
  }

  public Message(MessageWrapper wm){
    this(wm.getMessage());
  }

  public void disableAutoRetransmit() {
    this.retransmissions = Ant.maxRetransmissions;
  }

  public void retrasmitted() {
    this.retransmissions++;
  }

  public int getRetrasmissions() {
    return this.retransmissions;
  }

  public void invalidate(){
    this.delivered = true;
  }

  public boolean getDelivered(){
    return this.delivered;
  }

  public void resetDelivered() {
    this.delivered=false;
  }

  public void setDelivered() {
    this.delivered=true;
  }

  public void resetDest(){
    this.dest = "";
  }

  public void resetSource(){
    this.source = "";
  }

  public Message() {
    this.type = -1;
    this.ack_id = null;
    //Type 0 Messages
    //Type 1 Ack
    this.source = null;
    this.sourceAddress = "";
    this.dest = null;
    this.retransmissions = 0;
  }

  public void fillMessageProperties(String source, String sourceAddress, String dest, int type, String id_ack) {
    this.type = type;
    //Type 0 Messages
    //Type 1 Ack
    //Type 2 Discover
    this.ack_id = id_ack;
    this.source = source;
    this.sourceAddress = sourceAddress;
    this.dest = dest;
  }

  public int getType(){
    return this.type;
  }

  public String getAck_Id(){
    return this.ack_id;
  }

  public String getSource(){
    return this.source;
  }

  public String getSourceAddress(){
    return this.sourceAddress;
  }

  public String getDest(){
    return this.dest;
  }

  public boolean equals(Object o) {
    if (o instanceof MessageWrapper) {
      return ( (MessageWrapper) o).getMessage().getAck_Id().equals(this.getAck_Id()) &&
          ( (MessageWrapper) o).getMessage().getType() == this.getType();
    }
    else if (o instanceof QueryMessage) {
      return ( (QueryMessage) o).getAck_Id().equals(this.getAck_Id()) &&
          ( (QueryMessage) o).getType() == this.getType() &&
          ( (QueryMessage) o).getDest() == this.getDest();
    }
    else{
      try {
        return ( (Message) o).ack_id.equals(this.ack_id) &&
            ( (Message) o).type == this.type;
      }
      catch (ClassCastException e) {
        return o == this;
      }
    }
  }

  public void encrypt(Cipher enc)throws Exception{}
  public void decrypt(Cipher dec)throws Exception{}
}
